package com.coupon.settlement.executor.impl;

import com.alibaba.fastjson.JSON;
import com.coupon.common.constant.CouponCategoryEnum;
import com.coupon.common.vo.GoodsInfo;
import com.coupon.common.vo.SettlementInfo;
import com.coupon.settlement.constant.RuleFlagEnum;
import com.coupon.settlement.executor.AbstractExecutor;
import com.coupon.settlement.executor.RuleExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 王哲
 * @Contact 1121586359@qq.com
 * @ClassName ManJianZheKouExecutor.java
 * @create 2023年06月27日 下午2:54
 * @Description 满减折扣优惠券结算规则执行器
 * @Version V1.0
 */
@Slf4j
@Component
public class ManJianZheKouExecutor extends AbstractExecutor implements RuleExecutor {

    /**
     * 校验商品类型与优惠券是否匹配 满减 + 折扣
     *
     * @param settlement {@link SettlementInfo} 用户传递的结算信息
     * @return true/false
     */
    @Override
    protected boolean isGoodsTypeSatisfy(SettlementInfo settlement) {
        log.debug("Check ManJian And ZheKou Is Match Or Not!");
        List<Integer> goodsTypes = settlement.getGoodsInfos().stream()
                .map(GoodsInfo::getType)
                .collect(Collectors.toList());

        // 优惠券模板可用商品类型
        List<Integer> templateGoodsType = new ArrayList<>();

        settlement.getCouponAndTemplateInfos().forEach(ct -> {
            templateGoodsType.addAll(JSON.parseObject(
                    ct.getTemplateSDK().getRule().getUsage().getGoodsType(),
                    List.class
            ));
        });

        // 如果想要使用多张优惠券，必须要所有的优惠券都包含这个商品类型，才可以使用
        return CollectionUtils.isEmpty(
                CollectionUtils.subtract(goodsTypes, templateGoodsType)
        );
    }

    /**
     * 规则类型标记
     *
     * @return {@link RuleFlagEnum}
     */
    @Override
    public RuleFlagEnum ruleConfig() {
        return RuleFlagEnum.MANJIAN_ZHEKOU;
    }

    /**
     * 优惠券规则计算
     *
     * @param settlement {@link SettlementInfo} 包含了选择的优惠券
     * @return {@link SettlementInfo} 修正过的结算信息
     */
    @Override
    public SettlementInfo computeRule(SettlementInfo settlement) {
        // 商品总价
        double goodsSum = retain2Decimals(goodsCostSum(
                settlement.getGoodsInfos()
        ));
        // 判断商品类型与优惠券是否匹配
        SettlementInfo settlementInfo = processGoodsTypeNotSatisfy(
                settlement, goodsSum
        );

        if (settlementInfo != null) {
            log.debug("ManJian And ZheKou Template Is Not Match To GoodsType!");
            return settlementInfo;
        }

        SettlementInfo.CouponAndTemplateInfo manJian = null;
        SettlementInfo.CouponAndTemplateInfo zheKou = null;

        for (SettlementInfo.CouponAndTemplateInfo ct :
                settlement.getCouponAndTemplateInfos()) {
                  if (CouponCategoryEnum.of(ct.getTemplateSDK().getCategory())
                          == CouponCategoryEnum.MANJIAN) {
                      manJian = ct;
                  } else {
                      zheKou = ct;
                  }
        }
        assert manJian != null;
        assert zheKou != null;

        // 当前的折扣优惠券和满减券如果不能共用（一起使用），清空优惠券，返回商品原价
        if (!isTemplateCanShared(manJian, zheKou)) {
            log.debug("Current ManJian And ZheKou Can Not Shared!");
            settlement.setCost(goodsSum);
            settlement.setCouponAndTemplateInfos(Collections.emptyList());
            return settlement;
        }

        // 计算满减
        List<SettlementInfo.CouponAndTemplateInfo> ctInfos = new ArrayList<>();
        double manJianBase = (double) manJian.getTemplateSDK().getRule().getDiscount().getBase();
        double manJianQuota = (double) manJian.getTemplateSDK().getRule().getDiscount().getQuota();

        // 最终的价格
        double targetSum = goodsSum;
        // 先计算满减
        if (targetSum >= manJianBase) {
            targetSum -= manJianQuota;
            ctInfos.add(manJian);
        }

        // 计算折扣
        double zheKouQuota = (double) zheKou.getTemplateSDK().getRule().getDiscount().getQuota();
        targetSum *= zheKouQuota * 1.0 / 100;
        ctInfos.add(zheKou);

        settlement.setCouponAndTemplateInfos(ctInfos);
        settlement.setCost(retain2Decimals(
                targetSum > minCost() ? targetSum : minCost()
        ));

        return settlement;
    }

    /**
     * 判断满减和折扣是否可以共用
     * 即校验 TemplateRule 中的 weight 是否满足条件
     * @return
     */
    private boolean isTemplateCanShared(SettlementInfo.CouponAndTemplateInfo manJian,
                                        SettlementInfo.CouponAndTemplateInfo zheKou){

        String manJianKey = manJian.getTemplateSDK().getKey()
                + String.format("%04d", manJian.getTemplateSDK().getId());
        String zheKouKey = zheKou.getTemplateSDK().getKey()
                + String.format("%04d", zheKou.getTemplateSDK().getId());

        List<String> allSharedKeysForManJian = new ArrayList<>();
        allSharedKeysForManJian.add(manJianKey);
        allSharedKeysForManJian.addAll(JSON.parseObject(
                manJian.getTemplateSDK().getRule().getWeight(),
                List.class
        ));
        List<String> allSharedKeysForZheKou = new ArrayList<>();
        allSharedKeysForZheKou.add(zheKouKey);
        allSharedKeysForZheKou.addAll(JSON.parseObject(
                zheKou.getTemplateSDK().getRule().getWeight(),
                List.class
        ));

        return CollectionUtils.isSubCollection(
                Arrays.asList(manJianKey, zheKouKey), allSharedKeysForManJian)
                || CollectionUtils.isSubCollection(
                Arrays.asList(manJianKey, zheKouKey), allSharedKeysForZheKou);
    }

}
